<?php
/**
 * Description: 能力评估详情
 * User: devforma
 * Date: 15/4/10
 * Time: 15:31
 */

require __DIR__ . '/includes/utils.php';
class GetEvaluation implements iController {

    private $noteRate, $leafNoteLevel, $notes;

    /**
     * api请求处理主函数
     * @param array $queryArgs 就是$_REQUEST变量
     * @return array api返回结果，必须含response_code
     */
    public function output($queryArgs) {
        if (validateUser($queryArgs) !== 1)
            return genOutput(1000);

        $userId = $queryArgs['user_id'];

        $userData = getUserData($userId);
        if (empty($userData))
            return genOutput(1001);

        $examSummary = $this->getExamSummary($userData->exam_detail_id);

        $scores = array();
        $structureKeys = array('total_time', 'history_score', 'right_count');
        $summaryData = transformDataStructure(unserialize($userData->summary_info), $structureKeys);

        if (is_array($summaryData['history_score'])) {
            foreach ($summaryData['history_score'] as $date => $score) {
                $scores[] = array(
                    'date' => $date,
                    'score' => intval($score)
                );
            }
        }

        $examName = $this->getExamName($userData->exam_detail_id);
        if (empty($examName))
            $examName = '';

        $rank = getEvaluateRank($userData->exam_detail_id, $userData->score);

        return genOutput(1, array(
            'score' => intval($userData->score),
            'rank' => round($rank, 2),
            'learning_days' => $this->getLearningDays($userId),
            'total_time' => intval($summaryData['total_time']),
            'total_questions' => intval($userData->question_count),
            'avarage_questions' => intval($examSummary->question_count),
            'accuracy' => floatval($userData->accuracy),
            'avarage_accuracy' => floatval($examSummary->accuracy),
            'history_score' => $scores,
            'summary_source' => '全站'.$examName.'考生',
            'calculation_basis' => $examName.'最新大纲',
            'summary_date' => date('Y年m月d日'),
            'note_hierarchy' => $this->getNewFilteredHierarchy(normalizeUserNoteInfo($userData->note_info),
                $userData->exam_detail_id, !shouldShowNewNoteHierarchy($queryArgs['terminal_type'], $queryArgs['app_version']))
        ));
    }


    /**
     * 获取考试项目名称
     * @param int $examDetailId 考试id
     * @return null|string
     */
    private function getExamName($examDetailId) {
        global $cmsdb;

        $sql = 'SELECT e.exam_name FROM `data_exams` AS e INNER JOIN `data_exam_detail` AS ed ON e.exam_id=ed.exam_id
        AND ed.id='.$examDetailId;

        return $cmsdb->getVar($sql);

    }

    /**
     * 新版知识点层级结构
     *
     * @param array $userNotes 用户所选知识点范围
     * @param int $examId 考试项目id
     * @param bool $limitLevel 是否限制层数
     * @return array
     */
    private function getNewFilteredHierarchy(&$userNotes, $examId, $limitLevel = false) {
        $this->notes = getNewNoteHierarchy();

        if (empty($this->notes))
            return array();

        $this->noteRate = $this->getNoteRate($examId);
        $availableNotes = array_keys($userNotes);

        //抽离该用户所有叶子知识点的level
        foreach ($userNotes as $leafId => $leafNote) {
            $this->leafNoteLevel[$leafId] = $leafNote[3];
        }

        /**--------------------------------------------------------
         * 构造树形结构
         */
        $tree = array();
        $leafNotes = array();
        foreach ($this->notes as $noteId => $note) {
            $this->notes[$noteId]['level'] = 0;

            if ($note['note_type'] == 1) {
                if (!in_array($noteId, $availableNotes))
                    continue;

                $this->notes[$noteId]['level'] = intval($userNotes[$note['id']][3]);

                //叶子知识点数组
                $leafNotes[] = $this->notes[$noteId];
            }
        }

        //由叶子知识点构造知识点树,根节点直接进行覆盖处理,因为后面得出的根节点包含了前面处理时的结果
        foreach ($leafNotes as $leafNote) {
            $root = $this->findRoot($leafNote);
            $tree[$root['id']] = $root;
        }
        $tree = array_values($tree);


        /**--------------------------------------------------------------
         * 更新各知识点掌握程度
         */
        foreach ($tree as &$note) {
            $this->updateNoteLevel($note);
        }

        /**--------------------------------------------------------------
         * 老版App构造三层结构
         */
        if ($limitLevel) {
            $newTree = array();
            foreach ($tree as $catIndex => $category) {
                $newTree[$catIndex] = array(
                    'category_id' => $category['id'],
                    'level' => $category['level'],
                    'name' => $category['name'],
                    'note_group' => array()
                );

                if (!empty($category['childs'])) {
                    foreach ($category['childs'] as $groupIndex => $group) {
                        $newTree[$catIndex]['note_group'][$groupIndex] = array(
                            'group_id' => $group['id'],
                            'level' => $group['level'],
                            'name' => $group['name'],
                            'notes' => array()
                        );

                        if (!empty($group['childs'])) {
                            foreach ($group['childs'] as $noteIndex => $leafNote) {
                                $newTree[$catIndex]['note_group'][$groupIndex]['notes'][$noteIndex] = array(
                                    'note_id' => $leafNote['id'],
                                    'level' => $leafNote['level'],
                                    'name' => $leafNote['name']
                                );
                            }
                        }
                    }
                }
            }

            $tree = $newTree;
        }

        return $tree;
    }


    /**
     * 获取学习天数（有题目提交的日期才算）
     * @param int $userId 用户id
     * @return int
     */
    private function getLearningDays($userId) {
        global $cmsdb;
        $total = 0;

        $allRecords = $cmsdb->getCol("SELECT `action_time` FROM `qb_relationship_user_paper` WHERE `user_id`=:uid
        AND `status`=1", array(':uid' => $userId));

        if (empty($allRecords))
            return $total;

        $temp = array();
        foreach ($allRecords as $r) {
            $r2 = date('Y-m-d', strtotime($r));
            if (!isset($temp[$r2])) {
                $total++;
                $temp[$r2] = 0;
            }
        }

        return $total;
    }

    /**
     * 获取考试项目下的知识点考频
     *
     * @param int $examId 考试项目id
     * @return array
     */
    private function getNoteRate($examId) {
        global $cmsdb;

        $cacheKey = 'noteQuality:'.$examId;
        if (($data = cacheGet($cacheKey)) == null) {
            $notes = $cmsdb->getResults("SELECT `note_id`, `rate` FROM {$cmsdb->noteQuality} WHERE `testarea_id`=:exam_id",
                array(':exam_id' => $examId));

            $data = array();
            foreach ($notes as $note) {
                $data[$note->note_id] = $note->rate;
            }

            cacheAdd($cacheKey, $data, 12*60*60);
        }

        return $data;
    }

    /**
     * 获取排名和全站平均数据
     *
     * @param int $examDetailId
     * @return object
     */
    private function getExamSummary($examDetailId) {
        global $cmsdb;

        $cacheKey = 'func:getExamSummary'.$examDetailId;

        if (($data = cacheGet($cacheKey)) == null) {
            $sql = "SELECT AVG(`question_count`) AS `question_count`, AVG(`accuracy`) AS `accuracy` FROM `qb_user_data` 
            WHERE `exam_detail_id`={$examDetailId} ORDER BY `id` DESC LIMIT 100000";
            $data = $cmsdb->getRow($sql);

            cacheAdd($cacheKey, $data, 2*60*60);
        }

        return $data;
    }

    /**
     * 更新知识点掌握程度
     *
     * 每个知识点的掌握程度由该知识点下所有的叶子知识点计算得出,所以需要统计每层每个知识点下所属的叶子知识点
     *
     * @param array $note
     * @return mixed
     */
    private function updateNoteLevel(&$note) {
        $leafIds = array();
        if (!empty($note['childs'])) {
            $levelSum = $rateSum = 0;

            //获取该知识点下所有的叶子知识点
            foreach ($note['childs'] as &$child) {
                $leafIds = array_merge($leafIds, $this->updateNoteLevel($child));
            }

            //计算知识点掌握程度
            foreach ($leafIds as $leafId) {
                $levelSum += $this->leafNoteLevel[$leafId] * $this->noteRate[$leafId];
                $rateSum += $this->noteRate[$leafId];
            }
            $note['level'] = $levelSum/$rateSum;
            if ($note['level'] > 5)
                $note['level'] = 5;

        } else {
            $leafIds = array($note['id']);
        }

        //数值处理
        $note['level'] = round($note['level']);

        //去除知识点id索引
        $note['childs'] = array_values($note['childs']);

        return $leafIds;
    }

    /**
     * 查找指定知识点的父节点,并更新父子关系
     *
     * @param array $leafNote 子节点
     * @return array
     */
    private function findRoot(&$leafNote) {
        if (isset($this->notes[$leafNote['parent_id']])) {
            //如果该知识点的父知识点childs已经添加过该知识点了,则进行childs的合并
            if (isset($this->notes[$leafNote['parent_id']]['childs'][$leafNote['id']])) {
                foreach ($leafNote['childs'] as $key => $c) {
                    $this->notes[$leafNote['parent_id']]['childs'][$leafNote['id']]['childs'][$key] = $c;
                }
            } else {
                $this->notes[$leafNote['parent_id']]['childs'][$leafNote['id']] = $leafNote;
            }

            return $this->findRoot($this->notes[$leafNote['parent_id']]);
        }

        return $leafNote;
    }
}